package com.gitbl.webchat.roomnode;

import com.alibaba.fastjson.JSONObject;
import com.gitbl.webchat.message.JoinMessage;
import com.gitbl.webchat.message.RoomMessage;
import com.gitbl.webchat.service.RoomService;
import com.gitbl.webchat.utils.RedisHelper;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.concurrent.GlobalEventExecutor;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPipeline;
import redis.clients.jedis.ShardedJedisPool;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;


public class RoomsNode {

    NodeDetails nodeDetails;
    ShardedJedisPool redispool;
    static RoomsNode _instance;

    public static void init(){
        _instance = new RoomsNode();
    }
    public static RoomsNode instance() {
        return _instance;
    }

    RoomsNode() {
        wsFactory = new WebSocketServerHandshakerFactory(
                "", null, false);
        rooms = new HashMap<>();
        users = new HashMap<>();
        nodeDetails = new NodeDetails();
        String shosts = System.getProperty("cache.hosts");
        if(shosts==null||shosts.equals(""))
            shosts="127.0.0.1:6379";
        String[] hostsadd= shosts.split(",");

        redispool = RedisHelper.newPool(hostsadd);
    }

    Map<String, Room> rooms;
    Map<String, UserInfo> users;
    WebSocketServerHandshakerFactory wsFactory;

    private ChannelGroup GlobalGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private ConcurrentMap<String, ChannelId> ChannelMap = new ConcurrentHashMap();


    public WebSocketServerHandshaker newHandshaker(FullHttpRequest req) {
        return instance().wsFactory.newHandshaker(req);
    }

    boolean addRoom(String roomid, UserInfo usr) {
        Room room = rooms.get(roomid);
        if (room == null) {
            return false;
        }

        RoomMessage rm = nodeDetails.rooms.get(roomid);
        rm.setMember(rm.getMember() + 1);
        users.put(usr.channel.id().asLongText(), usr);
        return room.add(usr);
    }



    public void addChannel(Channel channel) {
        GlobalGroup.add(channel);
        ChannelMap.put(channel.id().asShortText(), channel.id());
    }


    public void removeChannel(Channel channel) {
        GlobalGroup.remove(channel);
        ChannelMap.remove(channel.id().asShortText());
    }




    public RoomMessage createRoom(String title, String owner) {
        Room r = new Room();
        r.title = title;
        r.id = UUID.randomUUID().toString();
        rooms.put(r.id, r);
        RoomMessage m = new RoomMessage();
        m.setMember(0);
        m.setOwner(owner);
        m.setAddress(nodeDetails.node.getAddress());
        m.setId(r.id);
        m.setTitle(title);
        nodeDetails.rooms.put(r.id, m);
        return m;
    }

    public void request(ChannelHandlerContext ctx, String request) {
        String id = ctx.channel().id().asLongText();
        //已认证
        if (users.containsKey(id)) {
            UserInfo u = users.get(id);
            Room ro = u.getRoom();
            ro.SendAll(u.username, request);
        } else { //未认证
            JoinMessage jm = JSONObject.parseObject(request, JoinMessage.class);
            if (jm == null) {
                ctx.channel().close();
                return;
            }
            Room r = rooms.get(jm.getRoomId());
            UserInfo u = new UserInfo();
            u.setChannel(ctx.channel());
            u.setRoom(r);
            u.setUsername(jm.getUsername());
            addRoom(jm.getRoomId(), u);
        }

    }

    public void updateOne(RoomMessage room){
        ShardedJedis rd = redispool.getResource();
        try {
            ShardedJedisPipeline pp = rd.pipelined();
            updateRoom(pp,room);
        }finally {
            rd.close();
        }
    }
    void updateRoom(ShardedJedisPipeline pp,RoomMessage room){
        String roomdata = JSONObject.toJSONString(room);
        pp.set(RoomService.KEY_ROOM_PRE + room.getId(), roomdata);
        pp.expire(RoomService.KEY_ROOM_PRE + room.getId(), 60);
        //roomtitle 用户模糊查询房间 id
        pp.set(RoomService.KEY_ROOM_TITLE_PRE + room.getTitle() + "." + room.getId(), "0");
        pp.expire(RoomService.KEY_ROOM_TITLE_PRE + room.getTitle() + "." + room.getId(), 60);
    }
    public void update() {
        ShardedJedis rd = redispool.getResource();
        try {
            ShardedJedisPipeline pp = rd.pipelined();
            String nodedata = JSONObject.toJSONString(nodeDetails.node);
            //更新节点信息
            pp.set(RoomService.KEY_NODE_PRE + nodeDetails.node.getAddress(), nodedata);
            pp.expire(RoomService.KEY_NODE_PRE + nodeDetails.node.getAddress(), 60);
            //更新房间信息
            for (RoomMessage item : nodeDetails.rooms.values()) {
                updateRoom(pp,item);
            }
            pp.sync();
        } finally {
            rd.close();
        }


    }

    public void close(Channel channel) {
        String chid = channel.id().asLongText();
        if (users.containsKey(chid)) {
            UserInfo u = users.get(chid);
            u.room.leave(u);
            users.remove(u);
            RoomMessage rm = nodeDetails.rooms.get(u.room.id);
            rm.setMember(rm.getMember() - 1);
        }

    }
}
